package com.easylinkin.linkappapi.security.utils;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * RSA加解密，登录用，秘钥对写死
 */
@Slf4j
public class RSAUtils {

    /**
     * base64编码后的公钥
     */
    private static final String publicKey =
            "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCKv0iHSj+fCuCUBO/JObTdh96SLmmNDMwf1OwMKzkIkt6CRRUfGcUNj5qDdT9UcATjKufEJ3TPgUI9GRW/iVwQRm6q2q7EbNu4v0DAMj3Z49Udg1f2ePG6gXUrNoD64yL2/WOgIYGKwIaCm+0lXYRHrBUILFHj+oECLKewEWqMqQIDAQAB";

    /**
     * base64编码后的私钥
     */
    private static final String privateKey =
            "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIq/SIdKP58K4JQE78k5tN2H3pIuaY0MzB/U7AwrOQiS3oJFFR8ZxQ2PmoN1P1RwBOMq58QndM+BQj0ZFb+JXBBGbqrarsRs27i/QMAyPdnj1R2DV/Z48bqBdSs2gPrjIvb9Y6AhgYrAhoKb7SVdhEesFQgsUeP6gQIsp7ARaoypAgMBAAECgYA4DucP+njQGoX4aDI1vEIOS6oqp+PvoF8M8WtZ01Dc3PJX8e+BvFi4jO/h80peJFBlNF2mDEcO2+vWYb8+vxHZzT/EunpWlfbJCvkkVPQ2+4qIaxDXovuRF4QpgP1HKp8FJ0nTJtcmmH6S/ifhJFhwZgc6BywbKCJ3mF1eT4hPsQJBALz7aOa1nc0msjF5T0Cv9wlMVTJIpuhl+dbvyZRaElkgyHpsc794ZrPOhsOYyupGGm92FTMY210VM3HOYz8SQKUCQQC781cL2ke75UJmvNyE125431m6UqlGq6MXPFRZGjZ0bXrRhL901k1TcstpKHAuhslBTckPCFecMmk3k5i+5/i1AkEAsOuE94fLZYX2iI6S/XI/CXtmvx5481SUov31b2crijlAtivV6MilDWwpie/+93gNw49+pUl+BBSXBtI6448I6QI/Mqhjzc4Hh51DSG2fAi8Ol4WbqZyeA24/hwO7uEhYZQkdEVu2PseED/ng2XcMxX2OwQs2JdcZxf/QXCpsAQiFAkEAjLoniFoXOCr4JAnvkx5GjVRlFAZkEl3utNE8JMJgsA4MkSMLOsUKgelvBh6NVn8/cjLeXzjgpuuvqGVkNQqgLQ==";

    /**
     * 算法
     */
    public static final String ALGORITHM_NAME = "RSA";

    /**
     * 秘钥位数
     */
    private static final int KeyBitNum = 1024;

    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = KeyBitNum / 8-11;

    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = KeyBitNum / 8;

    public static void main(String[] args) {
        try {
            String originData = "FQV4cZ%2FU5famUDGtIowbn%2B0G7umq%2FbX3%2FnMmgtxjOiaORRwTfBA%2BrQZGbFPNOQixPx4U6ZgEhrKTzT6QrHDXx0GU5Zy5wX%2BsQ4azFJtb4B3Yyqmlw4LNm2j5utxnkCixsEcXxIYtJHanYdrqAwp5tNwiqOsNR4Pn6HMAcq0Mc8g%3D";
            String decodedString = URLDecoder.decode(originData, "UTF-8");
            // RSA解密
            String decryptData = decrypt(decodedString);
            log.info("解密后内容:{}", decryptData);

        } catch (Exception e) {
            log.error("RSA加解密异常",e);
        }
    }

    /**
     * 生成密钥对
     * @return java.security.KeyPair
     */
    public static KeyPair getKeyPair() throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM_NAME);
        generator.initialize(1024);
        return generator.generateKeyPair();
    }

    /**
     * 获取私钥
     */
    public static PrivateKey getPrivateKey() throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_NAME);
        byte[] decodedKey = Base64.decodeBase64(privateKey.getBytes());
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
        return keyFactory.generatePrivate(keySpec);
    }

    /**
     * 获取公钥
     */
    public static PublicKey getPublicKey() throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_NAME);
        byte[] decodedKey = Base64.decodeBase64(publicKey.getBytes());
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
        return keyFactory.generatePublic(keySpec);
    }

    /**
     * RSA加密
     * @param data      待加密数据
     */
    public static String encrypt(String data) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
        PublicKey publicKey = getPublicKey();
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        int inputLen = data.getBytes().length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offset > 0) {
            if (inputLen - offset > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        // 获取加密内容使用base64进行编码,并以UTF-8为标准转化成字符串
        // 加密后的字符串
        return new String(Base64.encodeBase64(encryptedData));
    }

    /**
     * RSA解密
     * @param data 待解密数据
     */
    public static String decrypt(String data) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
        PrivateKey privateKey = getPrivateKey();
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] dataBytes = Base64.decodeBase64(data);
        int inputLen = dataBytes.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        //对数据分段解密
        while (inputLen - offset > 0) {
            if (inputLen - offset > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        // 解密后的内容
        return new String(decryptedData, StandardCharsets.UTF_8);
    }
}

